<template>
  <el-card class="spu-page">
    <!-- 工具栏 -->
    <div class="toolbar">
      <el-input v-model="filters.title" placeholder="SPU名称" class="toolbar-item" clearable @clear="onSearch" @keyup.enter="onSearch">
        <template #prefix><el-icon><Search /></el-icon></template>
      </el-input>
      <el-select v-model="filters.categoryId" placeholder="分类" class="toolbar-item" clearable filterable @change="onSearch">
        <el-option v-for="c in categoryOptions" :key="c.value" :label="c.label" :value="c.value" />
      </el-select>
      <el-select v-model="filters.brandId" placeholder="品牌" class="toolbar-item" clearable filterable @change="onSearch">
        <el-option v-for="b in brands" :key="b.id" :label="b.name" :value="b.id" />
      </el-select>
      <el-select v-model="filters.saleable" placeholder="上架状态" class="toolbar-item" clearable @change="onSearch">
        <el-option label="全部" :value="null" />
        <el-option label="上架" :value="1" />
        <el-option label="下架" :value="0" />
      </el-select>
      <el-button type="primary" @click="openDialog()">新增SPU</el-button>
      <el-button type="danger" :disabled="!multiple.length" @click="onBatchDelete">批量删除</el-button>
      <el-button @click="onExport">导出</el-button>
      <el-button @click="downloadTemplate">下载模板</el-button>
      <el-upload :before-upload="beforeImport" :show-file-list="false">
        <el-button>导入</el-button>
      </el-upload>
    </div>
    <!-- 表格 -->
    <el-table v-loading="loading" :data="list" stripe @selection-change="multiple = $event" style="width: 100%">
      <el-table-column type="selection" width="50" />
      <el-table-column prop="id" label="ID" width="80" />
      <el-table-column prop="title" label="名称" min-width="120" />
      <el-table-column prop="subTitle" label="副标题" min-width="120" />
      <el-table-column prop="categoryName" label="分类" min-width="100" />
      <el-table-column prop="brandName" label="品牌" min-width="100" />
      <el-table-column label="主图" width="100">
        <template #default="{ row }">
          <el-image :src="row.spuImage" style="width: 48px; height: 48px; border-radius: 8px; box-shadow: 0 1px 4px #ccc;" fit="cover" />
        </template>
      </el-table-column>
      <el-table-column prop="hasSpec" label="有规格" width="80">
        <template #default="{ row }">
          <el-tag :type="row.hasSpec === 1 ? 'success' : 'info'">{{ row.hasSpec === 1 ? '有' : '无' }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="saleable" label="上架" width="80">
        <template #default="{ row }">
          <el-tag :type="row.saleable === 1 ? 'success' : 'info'">{{ row.saleable === 1 ? '上架' : '下架' }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="valid" label="有效" width="80">
        <template #default="{ row }">
          <el-tag :type="row.valid === 1 ? 'success' : 'danger'">{{ row.valid === 1 ? '有效' : '无效' }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="createTime" label="创建时间" width="160" />
      <el-table-column label="操作" width="150" align="center" fixed="right">
        <template #default="{ row }">
          <div class="action-btns">
            <el-button type="primary" :icon="Edit" @click="openDialog(row)"></el-button>
            <el-button type="danger" :icon="Delete" @click="onDelete(row)"></el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页 -->
    <div class="pagination">
      <el-pagination background layout="prev, pager, next, jumper, sizes, total" :current-page="pageNum" :page-size="pageSize" :page-sizes="[10, 20, 50]" :total="total" @current-change="onPageChange" @size-change="onSizeChange" />
    </div>
    <!-- 新增/编辑弹窗 -->
    <el-dialog :title="dialogTitle" v-model="dialogVisible" width="520px">
      <el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
        <el-form-item label="名称" prop="title">
          <el-input v-model="form.title" autocomplete="off" />
        </el-form-item>
        <el-form-item label="副标题" prop="subTitle">
          <el-input v-model="form.subTitle" autocomplete="off" />
        </el-form-item>
        <el-form-item label="分类" prop="categoryId">
          <el-select v-model="form.categoryId" placeholder="选择分类" filterable clearable>
            <el-option v-for="c in categoryOptions" :key="c.value" :label="c.label" :value="c.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="品牌" prop="brandId">
          <el-select v-model="form.brandId" placeholder="选择品牌" filterable clearable>
            <el-option v-for="b in brands" :key="b.id" :label="b.name" :value="b.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="主图" prop="spuImage">
          <el-upload class="upload-demo" action="/common/admin/upload" :http-request="handleUploadRequest" :show-file-list="false" :before-upload="beforeUpload">
            <el-button size="small">上传主图</el-button>
          </el-upload>
          <div v-if="form.spuImage" class="image-preview">
            <img :src="form.spuImage" alt="主图" style="max-width: 100px; margin-top: 8px; border-radius: 8px; box-shadow: 0 1px 4px #ccc;" />
          </div>
        </el-form-item>
        <el-form-item label="有规格" prop="hasSpec">
          <el-radio-group v-model="form.hasSpec">
            <el-radio :label="1">有</el-radio>
            <el-radio :label="0">无</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="上架" prop="saleable">
          <el-radio-group v-model="form.saleable">
            <el-radio :label="1">上架</el-radio>
            <el-radio :label="0">下架</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="有效" prop="valid">
          <el-radio-group v-model="form.valid">
            <el-radio :label="1">有效</el-radio>
            <el-radio :label="0">无效</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="saving" @click="onSubmit">确定</el-button>
      </template>
    </el-dialog>
  </el-card>
</template>

<script setup>
import { ref, reactive, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Search, Edit, Delete } from "@element-plus/icons-vue";
import {
  pageSpu,
  getSpuDetail,
  addSpu,
  updateSpu,
  deleteSpu,
  exportSpu,
  downloadSpuTemplate,
  importSpu
} from "@/api/productSpu";
import { categoryTree } from "@/api/products";
import { pageBrands } from "@/api/products";
import { uploadFile } from "@/api/products";

// 查询参数
const filters = reactive({ title: "", categoryId: null, brandId: null, saleable: null });
const loading = ref(false);
const list = ref([]);
const total = ref(0);
const pageNum = ref(1);
const pageSize = ref(10);
const multiple = ref([]);

// 分类、品牌下拉
const categoryOptions = ref([]);
const brands = ref([]);

// 弹窗 & 表单
const dialogVisible = ref(false);
const isCreate = ref(true);
const dialogTitle = ref("新增SPU");
const form = reactive({ id: null, title: "", subTitle: "", categoryId: null, brandId: null, spuImage: "", hasSpec: 1, saleable: 1, valid: 1 });
const formRef = ref(null);
const saving = ref(false);

// 校验规则
const rules = {
  title: [{ required: true, message: "请输入SPU名称", trigger: "blur" }],
  categoryId: [{ required: true, message: "请选择分类", trigger: "change" }],
  spuImage: [{ required: true, message: "请上传主图", trigger: "change" }],
  hasSpec: [{ required: true, message: "请选择是否有规格", trigger: "change" }],
  saleable: [{ required: true, message: "请选择上架状态", trigger: "change" }],
};

// 拉取列表
async function fetchList() {
  loading.value = true;
  try {
    const params = {
      pageNum: pageNum.value,
      pageSize: pageSize.value,
      title: filters.title,
      categoryId: filters.categoryId,
      brandId: filters.brandId,
      saleable: filters.saleable,
    };
    const res = await pageSpu(params);
    list.value = res.data.items;
    total.value = res.data.total;
  } finally {
    loading.value = false;
  }
}

// 分类、品牌下拉
async function loadCategories() {
  const res = await categoryTree();
  // 转换为 el-option 格式
  function convert(list) {
    return list.map(item => ({
      value: item.id,
      label: item.name,
      ...(item.children ? { children: convert(item.children) } : {})
    }));
  }
  categoryOptions.value = convert(res.data || res.data.items || []);
}
async function loadBrands() {
  const res = await pageBrands({ pageNum: 1, pageSize: 100 });
  brands.value = res.data.items || [];
}

// 分页
function onPageChange(p) {
  pageNum.value = p;
  fetchList();
}
function onSizeChange(s) {
  pageSize.value = s;
  pageNum.value = 1;
  fetchList();
}
function onSearch() {
  pageNum.value = 1;
  fetchList();
}

// 新增/编辑
async function openDialog(row) {
  if (row) {
    isCreate.value = false;
    dialogTitle.value = "编辑SPU";
    const res = await getSpuDetail(row.id);
    Object.assign(form, res.data);
  } else {
    isCreate.value = true;
    dialogTitle.value = "新增SPU";
    Object.assign(form, { id: null, title: "", subTitle: "", categoryId: null, brandId: null, spuImage: "", hasSpec: 1, saleable: 1, valid: 1 });
  }
  dialogVisible.value = true;
}

// 提交表单
function onSubmit() {
  formRef.value.validate(async (valid) => {
    if (!valid) return;
    saving.value = true;
    try {
      if (isCreate.value) {
        await addSpu(form);
        ElMessage.success("新增成功");
      } else {
        await updateSpu(form);
        ElMessage.success("更新成功");
      }
      dialogVisible.value = false;
      fetchList();
    } finally {
      saving.value = false;
    }
  });
}

// 删除
function onDelete(row) {
  ElMessageBox.confirm("确认删除？", "提示", { type: "warning" }).then(
    async () => {
      await deleteSpu([row.id]);
      ElMessage.success("删除成功");
      fetchList();
    }
  );
}
// 批量删除
function onBatchDelete() {
  ElMessageBox.confirm("确认删除选中SPU？", "提示", { type: "warning" }).then(
    async () => {
      await deleteSpu(multiple.value.map((i) => i.id));
      ElMessage.success("批量删除成功");
      multiple.value = [];
      fetchList();
    }
  );
}
// 导出
function onExport() {
  exportSpu().then((res) => {
    const url = window.URL.createObjectURL(new Blob([res]));
    const a = document.createElement("a");
    a.href = url;
    a.download = "spu_list.xlsx";
    a.click();
    window.URL.revokeObjectURL(url);
  });
}
// 下载模板
function downloadTemplate() {
  downloadSpuTemplate().then((res) => {
    const url = window.URL.createObjectURL(new Blob([res]));
    const a = document.createElement("a");
    a.href = url;
    a.download = "spu_template.xlsx";
    a.click();
    window.URL.revokeObjectURL(url);
  });
}
// 导入
function beforeImport(file) {
  importSpu(file).then(() => {
    ElMessage.success("导入成功");
    fetchList();
  });
  return false;
}
// 主图上传
async function handleUploadRequest(option) {
  const formData = new FormData();
  formData.append("file", option.file);
  try {
    const res = await uploadFile(formData);
    form.spuImage = res.data;
    option.onSuccess(res.data);
    ElMessage.success("上传成功");
  } catch (err) {
    option.onError(err);
    ElMessage.error("上传失败");
  }
}
function beforeUpload(file) {
  const isImage = file.type.startsWith("image/");
  const isLt2M = file.size / 1024 / 1024 < 2;
  if (!isImage) ElMessage.error("上传文件须为图片");
  if (!isLt2M) ElMessage.error("图片大小不能超过2MB");
  return isImage && isLt2M;
}
onMounted(() => {
  loadCategories();
  loadBrands();
  fetchList();
});
</script>

<style scoped>
.spu-page {
  padding: 32px 16px 24px 16px;
  background: linear-gradient(135deg, #f8fafc 0%, #f0f4f8 100%);
  border-radius: 18px;
  box-shadow: 0 6px 32px 0 rgba(80,120,200,0.08);
  min-height: 90vh;
  transition: box-shadow 0.3s;
}
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 24px;
  align-items: center;
  background: rgba(255,255,255,0.85);
  border-radius: 14px;
  box-shadow: 0 2px 12px 0 rgba(80,120,200,0.06);
  padding: 18px 18px 10px 18px;
  animation: fadeInDown 0.7s;
}
@keyframes fadeInDown {
  from { opacity: 0; transform: translateY(-20px); }
  to { opacity: 1; transform: none; }
}
.toolbar-item {
  width: 150px;
  min-width: 120px;
  transition: box-shadow 0.2s, border-color 0.2s;
}
.toolbar-item .el-input__wrapper,
.toolbar-item .el-select__wrapper {
  border-radius: 8px;
  box-shadow: 0 1px 4px 0 rgba(80,120,200,0.04);
}
.toolbar-item .el-input__wrapper:hover,
.toolbar-item .el-select__wrapper:hover {
  border-color: #6c8cff;
  box-shadow: 0 2px 8px 0 rgba(80,120,200,0.10);
}
.el-button[type="primary"] {
  background: linear-gradient(90deg, #6c8cff 0%, #88e0ef 100%);
  border: none;
  color: #fff;
  font-weight: 500;
  box-shadow: 0 2px 8px 0 rgba(80,120,200,0.10);
  transition: background 0.2s, box-shadow 0.2s;
}
.el-button[type="primary"]:hover {
  background: linear-gradient(90deg, #88e0ef 0%, #6c8cff 100%);
  color: #fff;
}
.el-button[type="danger"] {
  background: linear-gradient(90deg, #ff6c6c 0%, #ffb88c 100%);
  border: none;
  color: #fff;
  font-weight: 500;
  box-shadow: 0 2px 8px 0 rgba(255,108,108,0.10);
  transition: background 0.2s, box-shadow 0.2s;
}
.el-button[type="danger"]:hover {
  background: linear-gradient(90deg, #ffb88c 0%, #ff6c6c 100%);
  color: #fff;
}
.action-btns {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-width: 100px;
}
.el-table {
  border-radius: 14px;
  overflow: hidden;
  background: rgba(255,255,255,0.98);
  box-shadow: 0 2px 16px 0 rgba(80,120,200,0.07);
  animation: fadeIn 0.7s;
}
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.el-table th {
  background: linear-gradient(90deg, #f0f4ff 0%, #f8fafc 100%);
  color: #4a5a7a;
  font-weight: 600;
  font-size: 15px;
}
.el-table tr {
  transition: background 0.2s;
}
.el-table tr:hover {
  background: #eaf3ff !important;
}
.el-table .el-table__row.selected {
  background: #d6e4ff !important;
}
.el-table .el-button {
  border-radius: 8px;
  font-size: 15px;
  min-width: 64px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 2px;
  box-shadow: 0 1px 4px 0 rgba(80,120,200,0.08);
  transition: background 0.2s, transform 0.2s;
}
.el-table .el-button:hover {
  background: linear-gradient(90deg, #6c8cff 0%, #88e0ef 100%);
  color: #fff;
  transform: scale(1.08);
}
.pagination {
  text-align: center;
  margin-top: 24px;
}
.el-pagination {
  border-radius: 10px;
  background: rgba(255,255,255,0.85);
  box-shadow: 0 2px 8px 0 rgba(80,120,200,0.06);
  padding: 8px 16px;
}
.el-dialog {
  border-radius: 18px !important;
  box-shadow: 0 8px 40px 0 rgba(80,120,200,0.18) !important;
  animation: fadeInUp 0.5s;
}
@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(40px); }
  to { opacity: 1; transform: none; }
}
.el-dialog__header {
  font-size: 22px;
  font-weight: 700;
  color: #3a4a6a;
  letter-spacing: 1px;
}
.el-dialog__footer {
  background: #f8fafc;
  border-radius: 0 0 18px 18px;
  padding: 18px 24px;
}
.el-form-item__label {
  font-weight: 600;
  color: #3a4a6a;
  font-size: 15px;
}
.el-form-item .el-input__wrapper,
.el-form-item .el-select__wrapper {
  border-radius: 8px;
  box-shadow: 0 1px 4px 0 rgba(80,120,200,0.04);
  transition: box-shadow 0.2s, border-color 0.2s;
}
.el-form-item .el-input__wrapper:focus-within,
.el-form-item .el-select__wrapper:focus-within {
  border-color: #6c8cff;
  box-shadow: 0 2px 8px 0 rgba(80,120,200,0.10);
}
/* 响应式 */
@media screen and (max-width: 1024px) {
  .spu-page {
    padding: 8px 2px 12px 2px;
  }
  .toolbar {
    flex-direction: column;
    gap: 10px;
    padding: 12px 8px 6px 8px;
  }
  .action-btns {
    min-width: 80px;
  }
  .el-table th, .el-table td {
    font-size: 13px;
  }
}
@media screen and (max-width: 768px) {
  .spu-page {
    padding: 2px 0 6px 0;
    min-height: unset;
  }
  .toolbar {
    flex-direction: column;
    gap: 8px;
    padding: 8px 2px 4px 2px;
  }
  .toolbar-item {
    min-width: 90px;
    width: 100%;
  }
  .el-table th, .el-table td {
    font-size: 12px;
    padding: 4px 2px;
  }
  .el-dialog {
    width: 98vw !important;
    min-width: unset;
    padding: 0;
  }
}
</style> 